package cn.ddiancan.auth.service.provider;

import cn.ddiancan.auth.constant.RequestTypeEnum;
import cn.ddiancan.auth.service.token.XddAuth2SmsCodeAuthenticationToken;
import cn.ddiancan.auth.service.userdetails.XddcloudUserDetailsImpl;
import cn.ddiancan.xddcloud.ddccore.cache.XddCloudCacheClient;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

@RequiredArgsConstructor
public class XddOAuth2SmsCodeAuthenticationProvider implements AuthenticationProvider {

    private static final String SMS_EXPIRE_CACHE_KEY = "sms_expire_cache_key:";

    private final OAuth2TokenGenerator<?> tokenGenerator;

    private final JwtEncoder jwtEncoder;

    private final XddcloudUserDetailsImpl userDetailService;

    private final OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer;

    private final AuthorizationServerSettings authorizationServerSettings;

    private final OAuth2AuthorizationService oAuth2AuthorizationService;

    private final XddCloudCacheClient xddCloudCacheClient;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        XddAuth2SmsCodeAuthenticationToken xddAuth2UserCodeAuthenticationToken =
            (XddAuth2SmsCodeAuthenticationToken) authentication;
        String smsCode = xddAuth2UserCodeAuthenticationToken.getSmsCode();
        String phoneNumber = xddAuth2UserCodeAuthenticationToken.getPhoneNumber();
        Assert.isTrue(StringUtils.hasText(smsCode), "验证码不能为空");
        Assert.isTrue(StringUtils.hasText(phoneNumber), "手机号不能为空");
        // 查到商户，验证验证码
        String cacheKey = SMS_EXPIRE_CACHE_KEY.concat(phoneNumber.trim());
        String hasSendedCode = xddCloudCacheClient.get(cacheKey);
        Assert.isTrue(smsCode.equals(hasSendedCode), "验证码已失效");
        userDetailService.setRequestSource(xddAuth2UserCodeAuthenticationToken.getRequestSource());
        userDetailService.setLoginType(RequestTypeEnum.valueOf(xddAuth2UserCodeAuthenticationToken.getRequestType()));
        UserDetails userDetails = userDetailService.loadUserByUsername(phoneNumber);
        return OAuth2AccessTokenAuthenticationTokenHelper.auth2AccessTokenAuthenticationToken(
            xddAuth2UserCodeAuthenticationToken, userDetails, authorizationServerSettings, jwtCustomizer,
            oAuth2AuthorizationService, tokenGenerator, jwtEncoder);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return XddAuth2SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
